import pickle

import base64

from django_redis import get_redis_connection
from rest_framework import status

from rest_framework.response import Response

from rest_framework.views import APIView

from carts.serializers import CartSerializer, CartSKUSerializer

from django.http.response import JsonResponse

from goods.models import SKU


class CartAPIView(APIView):

    def perform_authentication(self, request):
        pass

    def post(self,request):
        # 1.后端接收这些数据(sku_id,count,selected)
        data=request.data
        # 2.检验数据
        serializer=CartSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        # 3.校验之后再获取这些数据
        sku_id=serializer.validated_data.get('sku_id')
        count=serializer.validated_data.get('count')
        selected=serializer.validated_data.get('selected')
        # 4.获取用户信息
        try:

            user=request.user
        except Exception:
            user=None
        # 5.根据用户信息进行判断
        # is_authenticated 认证过的，也就是说是登录的用户
        if user is not None and user.is_authenticated:
            # 6.登录用户redis
            #   6.1连接redis
            redis_conn=get_redis_connection('cart')
            #   6.2保存数据
            # hash
            # redis_conn.hset('cart_%s'%user.id,sku_id,count)
            # # set 集合
            # if selected:
            #     redis_conn.sadd('cart_selected_%s'%user.id,sku_id)
            pl=redis_conn.pipeline()
            pl.hincrby('cart%s'%user.id,sku_id,count)
            if selected:
                pl.sadd('cart_selected_%s'%user.id,sku_id)
            pl.excute()
            # 6.3返回响应
            return Response(serializer.data)
        else:
            # 7.未登录用户cookie
            #接收数据了      1：count：1 selected：True
            #   7.1先获取cookie信息
            cookie_str=request.COOKIES.get('cart')
            #   7.2判断cookie信息中，是否有购物车的信息
            if cookie_str is not None:
                #       如果有cookie信息是经过base64加密的，现在要解密
                # 7.2.1 先将字符串经过base64 解密
                bytes_data=base64.b64decode(cookie_str)
                # 7.2.2 将解密的二进制 进行字典转换
                cookie_cart=pickle.loads(bytes_data)

            else:
                #   如果没有
                cookie_cart={}
                #       cookie_cart={1:{'count':2,'selected':True}}
                #   7.3 判断商品是否存在cookie的购物车中
            if sku_id in cookie_cart:
                #   如果有则累加个数
                original_count=cookie_cart[sku_id]['count']
                # count=count+original_count
                count+=original_count

            #更新数据
                #       如果没有 则将接收的数据 添加到cookie购物车中
            cookie_cart[sku_id]={
                'count':count,
                'selected':selected
            }

            #   7.4 对字典数据进行转换   ‘abcde’
            # 7.4.1 将字典转换为二进制
            byted_dumps=pickle.dumps(cookie_cart)
            # 7.4.2 对二进制进行base64编码
            bytes_str=base64.b64encode(byted_dumps)
            # 7.4.3 获取字符串
            cookie_save_str=bytes_str.decode()
            #   7.5 设置cookie
            response=Response(serializer.data)

            response.set_cookie('cart',cookie_save_str,3600)

            #   返回响应
            return response

    def get(self,request):
        # 1.获取用户信息
        try:
            user=request.user
        except Exception:
            user=None
        # 2.判断用户信息
        if user is not None and user.is_authenticated:
            # 3. 登录用户从redis中获取数据
            # 3.1 连接redis
            redis_conn=get_redis_connection('cart')
            # 获取redis的数据，hash set sku_id:count,sku_id:count
            #hash
            #{sku_id:count,sku_id:count}
            redis_ids_count=redis_conn.hgetall('cart_%s'%user.id)

            #set
            #{sku_id,sku_id}
            redis_selected_ids=redis_conn.smembers('cart_selected%s'%user.id)
            # 额外做一步，统一数据格式
            #将redis数据转换为cookie数据格式

            cookie_cart={}
            #{sku_id:{count:XXX,selected:XXX}
            #对redis数据进行遍历
            for id,count in redis_ids_count.items():
                #判断 遍历的id是否在选中的列表中
                if id in redis_selected_ids:
                    selected=True
                else:
                    selected=False
                cookie_cart[int(id)]={
                    'count':int(count),
                    #'selected':id in redis_selected_ids
                    'selected':selected
                }

        else:
            # 4.未登录用户从cookie中获取数据
    #       4.1 从cookie中获取数据
            cookie_str=pickle.COOKIES.get('cart')
            #   4.2判断数据是否存在
            if cookie_str is not None:
                #如果存在则要进行解码
            #{sku_id:{count:XXX,selected:XXX}}
                cookie_cart=pickle.loads(base64.b64decode(cookie_str))
            else:
                #如果不存在
                cookie_cart={}
        # 5.    获取商品的所有的id  【id,id,id】
                # 或企业字典中的所有key
        ids=cookie_cart.keys()
        skus=SKU.objects.filter(pk__in=ids)
        # 额外添加一步，对列表数据进行遍历，动态添加 count和selected
        #{sku_id:{count:XXX,selected:XXX}}
        #从cookie_cart 中获取 count和 selected
        for sku in skus:
            sku.count=cookie_cart[sku.id]['count']
            sku.selected=cookie_cart[sku.id]['selected']

        # 7.将对象列表转换为字典
        serializer=CartSKUSerializer(skus,many=True)
        return Response(serializer.data)

    def put(self,request):
        # 1.接收数据
        data=request.data
        # 2.校验数据
        serializer=CartSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        # 3.获取校验后的数据
        sku_id=serializer.validated_data.get('sku_id')
        count=serializer.validated_data.get('count')
        selected=serializer.validated_data.get('selected')
        # 4.获取用户信息
        try:
            user=request.user
        except Exception:
            user=None
        # 5.根据用户信息进行判断
        if user is not None and user.is_authenticated:
            # 6.登录用户redis
            #   6.1连接redis
            redis_conn=get_redis_connection('cart')
            #   6.2 更新数据
            # hash
            redis_conn.hset('cart_%s'%user.id,sku_id,count)
            # set
            if selected:
                redis_conn.sadd('cart_selected_%s'%user.id,sku_id)
            else:
                redis_conn.srem('cart_selected_%s'%user.id,sku_id)
            #       6.3 返回响应（要注意，把数据返回给前端）
            return Response(serializer.data)

        else:
            # 7.未登录用户cookie
        #   7.1先获取cookie数据
            cookie_str=request.COOKIES.get('cart')
            #   7.2判断cookie数据是否存在
            if cookie_str is not None:
                #如果存在则进行解密
                cookie_cart=pickle.loads(base64.b64decode(cookie_str))
            else:
                cookie_cart={}
        #   7.3 更新数据
                # {水库——id：{count:XXX,selected:XXX}}
            if sku_id in cookie_cart:
                cookie_cart[sku_id]={
                    'count':count,
                    'selected':selected
                }
            #   7.4 对字典进行加密
            cookie_save_str=base64.b64encode(pickle.dumps(cookie_cart)).decode()
            #   7.5 设置cookie数据
            response=Response(selected.data)

            response.set_cookie('cart',cookie_save_str,3600)

            #   7.6 返回响应
            return response


    def delete(self,request):

        #1. 接收商品id
        data=request.data
        # 2.验证商品id（验证省略）
        sku_id=data.get('sku_id')
        # 3.获取用户信息
        try:
            user=request.user
        except Exception:
            user=None
        # 4.根据用户进行判断
        if user is not None and user.is_authenticated:
            #5.登录用户操作redis
            #   5.1连接redis
            redis_conn=get_redis_connection('cart')
            #   5.2删除数据hash，set
            #hash
            redis_conn.hdel('cart_%s'%user.id,sku_id)
            #set
            redis_conn.srem('cart_selected_%s'%user.id,sku_id)

            #   5.3 返回响应
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            # 6。未登录用户操作cookie
            #   6.1先获取cookie数据
            cookie_str=request.COOKIES.get('cart')
            #   6.2判断cookie数据是否存在
            if cookie_str is not None:
                cookie_cart=pickle.loads(base64.b64decode(cookie_str))
            else:
                cookie_cart={}
            #   6.3 删除
            if sku_id in cookie_cart:
                del cookie_cart[sku_id]
            #   6.4 将字典进行加密
            cookie_save_str=base64.b64encode(pickle.dumps(cookie_cart))
            #   6.5设置cookie，返回响应
            response=Response(status=status.HTTP_204_NO_CONTENT)

            response.set_cookie('cart',cookie_save_str,3600)

            return response

